home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 3 / Cream of the Crop 3.iso / comm / wnos5src.zip / NRCMD.C < prev    next >
Text File  |  1993-08-09  |  26KB  |  1,164 lines

  1. /* net/rom user command processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <ctype.h>
  8. #include <time.h>
  9. #include <string.h>
  10. #include "global.h"
  11. #include "config.h"
  12. #ifdef NETROM
  13. #include "mbuf.h"
  14. #include "ax25.h"
  15. #include "mailbox.h"
  16. #include "netrom.h"
  17. #include "nr4.h"
  18. #include "timer.h"
  19. #include "iface.h"
  20. #include "cmdparse.h"
  21. #include "session.h"
  22. #include "socket.h"
  23. #include "commands.h"
  24. #include "files.h"
  25.  
  26. /* Nodes message broadcast address: "NODES" in shifted ASCII */
  27. /* defined in ax25rout.c: Ax25multi[1] */
  28.  
  29. char Nr4user[AXALEN];
  30.  
  31. char *Nr4states[] = {
  32.     "Disconnected",
  33.     "Conn Pending",
  34.     "Connected",
  35.     "Disc Pending",
  36.     "Listen (S)"
  37. } ;
  38.  
  39. char *Nr4reasons[] = {
  40.     "Normal",
  41.     "By Peer",
  42.     "Timeout",
  43.     "Reset",
  44.     "Refused"
  45. } ;
  46.  
  47. int Nr_save = 1;     /* NET/ROM Route Save on by default */
  48. int donrsave __ARGS((void));
  49.  
  50. static char *Nodelist = NULLCHAR;
  51. static struct timer Nodetimer ;    /* timer for nodes broadcasts */
  52. static struct timer Obsotimer ;    /* timer for aging routes */
  53. static char badcall[] = "Bad destination callsign\n";
  54. static char badnb[] = "Bad neighbor callsign\n";
  55.  
  56. int
  57. doroutedump(int argc,char *argv[],void *p)
  58. {
  59. #define MAX_LES_ROUTES    150
  60.  
  61.     struct nrroute_tab *rp ;
  62.     char buf[18], temp[18], les_routes[MAX_LES_ROUTES][18], *cp;
  63.     int count = 0, column = 1, in, out, i;
  64.  
  65.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  66.         for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  67.             if(count > MAX_LES_ROUTES - 1)
  68.                 break;
  69.             strcpy(buf,rp->alias) ;
  70.             /* remove trailing spaces */
  71.             if ((cp = strchr(buf,' ')) == NULLCHAR)
  72.                 cp = &buf[strlen(buf)] ;
  73.             if (cp != buf)          /* don't include colon for null alias */
  74.                 *cp++ = ':' ;
  75.             pax25(cp,rp->call) ;
  76.             if(argc == 9) {
  77.                 if (buf[0] != '#') {                  /* NREX bke 920809 */
  78.                   count++;
  79.                   strcpy(les_routes[count],buf);
  80.                 }
  81.                 continue;
  82.             }
  83.             if(argc == 10) {                          /* NREX bke 920809 */
  84.                 count++;
  85.                 strcpy(les_routes[count],buf);
  86.                 continue;
  87.             }                                         /* bke */
  88.             if(strstr(buf,"TCP") != NULL
  89.               || strstr(buf,"NOS") != NULL
  90.               || strstr(buf,"IP") != NULL) {
  91.                 count++;
  92.                 strcpy(les_routes[count],buf);
  93.             }
  94.         }
  95.         if(count > MAX_LES_ROUTES - 1) {
  96.             tprintf("\nOnly %d routes displayed\n",MAX_LES_ROUTES);
  97.             break;
  98.         }
  99.     }
  100.     for (out = 1; out < count; out++)
  101.         for (in = out+1; in < count+1; in++)
  102.             if (strcmp(les_routes[out],les_routes[in]) > 0 ) {
  103.                 strcpy(temp, les_routes[in]);
  104.                 strcpy(les_routes[in], les_routes[out]);
  105.                 strcpy(les_routes[out], temp);
  106.             }
  107.  
  108.     for(i = 1; i <= count; i++) {
  109.         tprintf("%-16s  ", les_routes[i]);
  110.         if( column++ == 4) {
  111.             tputs("\n");
  112.             column = 1;
  113.         }
  114.     }
  115.     if(column != 1)
  116.         tputs("\n");
  117.     return 0 ;
  118. }
  119.  
  120. /* print detailed information on an individual route */
  121. int
  122. dorouteinfo(int argc,char *argv[],void *p)
  123. {
  124.     struct nrroute_tab *rp ;
  125.     struct nr_bind *bp ;
  126.     struct nrnbr_tab *np ;
  127.     char dest[AXALEN], neighbor[AXBUF], alias[AXBUF], *cp;
  128.  
  129.     if (setcall(dest,argv[1]) == -1) {
  130.         tputs (badcall);
  131.         return -1 ;
  132.     }
  133.  
  134.     if(putalias(alias,argv[1],0) != -1
  135.       && (cp = find_nralias(alias)) != NULLCHAR)
  136.         memcpy(dest,cp,AXALEN);
  137.  
  138.     if((rp = find_nrroute(dest)) == NULLNRRTAB) {
  139.         if(argc < 9)
  140.             tprintf("*** no route to %s\n",pax25(neighbor,dest)) ;
  141.         return -1 ;
  142.     }
  143.  
  144.     for (bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  145.         np = bp->via ;
  146.         if(tprintf("%1s %3d  %3d  %-8s  %s\n",
  147.          (bp->flags & NRB_PERMANENT ? "P" :
  148.          bp->flags & NRB_RECORDED ? "R" : " "),
  149.          bp->quality,bp->obsocnt,
  150.          Nrifaces[np->iface].iface->name,
  151.          pax25(neighbor,np->call)) == EOF)
  152.             break;
  153.     }
  154.     return 0 ;
  155. }
  156.  
  157. /* convert a null-terminated alias name to a blank-filled, upcased */
  158. /* version.  Return -1 on failure. */
  159. int
  160. putalias(char *to,char *from,int complain)
  161. {
  162.     int len, i ;
  163.  
  164.     if ((len = strlen(from)) > ALEN) {
  165.         if (complain)
  166.             tputs ("Max six chars\n") ;
  167.         return -1 ;
  168.     }
  169.  
  170.     for (i = 0 ; i < ALEN ; i++) {
  171.         if (i < len) {
  172.             if (islower(*from))
  173.                 *to++ = toupper(*from++) ;
  174.             else
  175.                 *to++ = *from++ ;
  176.         }
  177.         else
  178.             *to++ = ' ' ;
  179.     }
  180.  
  181.     *to = '\0' ;
  182.     return 0 ;
  183. }
  184.  
  185. /* find a netrom interface, gives a msg if 'msg' is set != 0 */
  186. static int near
  187. nrif_lookup(char *call,int msg)
  188. {
  189.     int i;
  190.  
  191.     for (i = 0 ; i < Nr_numiface ; i++)
  192.         if (!strcmp(Nrifaces[i].iface->name,call))
  193.             break ;
  194.     if (i == Nr_numiface) {
  195.         if(msg)
  196.             tprintf(Badif,call);
  197.         return -1 ;
  198.     }
  199.     return i;
  200. }
  201.  
  202. /* Add a route */
  203. static int
  204. dorouteadd(int argc,char *argv[],void *p)
  205. {
  206.     char alias[AXALEN], dest[AXALEN], neighbor[AXALEN];
  207.     unsigned quality ;
  208.     int i ;
  209.  
  210.     /* format alias (putalias prints error message if necessary) */
  211.     if (putalias(alias,argv[1],1) == -1)
  212.         return -1 ;
  213.  
  214.     /* format destination callsign */
  215.     if (setcall(dest,argv[2]) == -1) {
  216.         tputs(badcall);
  217.         return -1 ;
  218.     }
  219.  
  220.     if((i = nrif_lookup(argv[3],1)) == -1)
  221.         return -1;
  222.  
  223.     /* format neighbor address string */
  224.     if (setcall(neighbor,argv[5]) == -1) {
  225.         tputs(badcall);
  226.         return -1;
  227.     }
  228. #ifdef XXX
  229.     /* Change from 871225 -- no digis in net/rom table */
  230.     if (argc > 6)
  231.         tputs("digis given: set route with ax25 route cmd\n");
  232. #endif
  233.     /* get and check quality value */
  234.     quality = (unsigned)min(atoi(argv[4]),255);
  235.  
  236.     return nr_routeadd(alias,dest,i,quality,neighbor,1,0) ;
  237. }
  238.  
  239.  
  240. /* drop a route */
  241. static int
  242. doroutedrop(int argc,char *argv[],void *p)
  243. {
  244.     char dest[AXALEN], neighbor[AXALEN] ;
  245.     int i ;
  246.  
  247.     /* format destination and neighbor callsigns */
  248.     if (setcall(dest,argv[1]) == -1) {
  249.         tputs(badcall);
  250.         return -1 ;
  251.     }
  252.     if (setcall(neighbor,argv[2]) == -1) {
  253.         tputs(badnb);
  254.         return -1 ;
  255.     }
  256.  
  257.     if((i = nrif_lookup(argv[3],1)) == -1)
  258.         return -1;
  259.  
  260.     return nr_routedrop(dest,neighbor,i) ;
  261. }
  262.  
  263. /* make an interface available to net/rom */
  264. static int
  265. dointerface(int argc,char *argv[],void *p)
  266. {
  267.     int i ;
  268.     struct iface *ifp ;
  269.  
  270.     if (Nr_iface == NULLIF)
  271.         nr_attach(0,0,p);
  272.  
  273.     if (Nr_numiface >= NRNUMIFACE) {
  274.         tprintf("Max %d NET/ROM ifaces\n",NRNUMIFACE);
  275.         return 1 ;
  276.     }
  277.     if((ifp = if_lookup(argv[1])) == NULLIF){
  278.         tprintf(Badif,argv[1]);
  279.         return 1;
  280.     }
  281.     for (i = 0 ; i < Nr_numiface ; i++)
  282.         if (Nrifaces[i].iface == ifp) {
  283.             tprintf("Iface %s already registered\n",argv[1]) ;
  284.             return 1 ;
  285.         }
  286.  
  287.     Nrifaces[Nr_numiface].iface = ifp ;
  288.  
  289.     /* NREX bke 920716 */
  290.     if(argc == 5) {
  291.         if(setcall(Nrifaces[Nr_numiface].call,argv[4]) == -1)
  292.             return 1;
  293.     } else {
  294.         memcpy(Nrifaces[Nr_numiface].call,Mycall,AXALEN);
  295.     }
  296.  
  297.     if (putalias(Nrifaces[Nr_numiface].alias,argv[2],1) == -1)
  298.         return 1 ;
  299.  
  300.     Nrifaces[Nr_numiface].quality = (unsigned)min(atoi(argv[3]),255);
  301.     Nr_numiface++ ;                    /* accept this interface */
  302.     return 0 ;
  303. }
  304.  
  305. static void
  306. donodetick(void)
  307. {
  308.     if(Nr_numiface) {
  309.         int i;
  310.  
  311.         stop_timer(&Nodetimer);
  312.  
  313.         for (i = 0 ; i < Nr_numiface ; i++)
  314.             nr_bcnodes(i,Ax25multi[1]) ;
  315.  
  316.         if(strchr(Nodelist,'*') != NULLCHAR) {
  317.             char *cp1 = strxdup(Nodelist);
  318.             char *cp = strtok(cp1,"*");
  319.  
  320.             while((cp = strtok(NULL,"*")) != NULLCHAR)
  321.                 nr_bcnodes(Nr_numiface - 1,cp);
  322.  
  323.             xfree(cp1);
  324.         }
  325.     }
  326.     /* restart timer */
  327.     start_timer(&Nodetimer);
  328. }
  329.  
  330. /* Broadcast nodes list on named interface. */
  331. static int
  332. dobcnodes(argc,argv,p)
  333. int argc ;
  334. char *argv[] ;
  335. void *p;
  336. {
  337.     int j;
  338.     char call[AXALEN];
  339.  
  340.     int i = nrif_lookup(argv[1],(argc < 3) ? 1 : 0);
  341.  
  342.     if(argc < 3) {
  343.         if(i == -1)
  344.             return -1;
  345.         nr_bcnodes(i,Ax25multi[1]);
  346.         return 0;
  347.     }
  348.     if(i == -1) {
  349.         argc++;
  350.         argv--;
  351.     }
  352.     if(Nodelist) {
  353.         xfree(Nodelist);
  354.     }
  355.     Nodelist = cxallocw(argc + 1,AXBUF);
  356.  
  357.     for(j = 1; j < argc; j++) {
  358.         if(setcall(call,argv[j]) == -1)
  359.             continue;
  360.         strcat(Nodelist,call);
  361.         strcat(Nodelist,"*");
  362.     }
  363.     donodetick();
  364.     return 0;
  365. }
  366.  
  367. /* Set outbound node broadcast interval */
  368. static int
  369. donodetimer(argc,argv,p)
  370. int argc;
  371. char *argv[];
  372. void *p;
  373. {
  374.     if(argc < 2){
  375.         tprintf("Nodetimer %lu/%lu s\n",
  376.             read_timer(&Nodetimer)/1000L,
  377.             dur_timer(&Nodetimer)/1000L);
  378.         return 0;
  379.     }
  380.     /* in case it's already running */
  381.     stop_timer(&Nodetimer) ;
  382.     /* what to call on timeout */
  383.     Nodetimer.func = (void (*) __ARGS((void *))) donodetick;
  384.     Nodetimer.arg = NULLCHAR;                        /* dummy value */
  385.     set_timer(&Nodetimer,atol(argv[1]) * 1000L);    /* set timer duration */
  386.     start_timer(&Nodetimer);                        /* and fire it up */
  387.     return 0;
  388. }
  389.  
  390. /* Go through the routing table, reducing the obsolescence count of
  391.  * non-permanent routes, and purging them if the count reaches 0
  392.  */
  393. static void
  394. doobsotick()
  395. {
  396.     struct nrnbr_tab *np ;
  397.     struct nrroute_tab *rp, *rpnext ;
  398.     struct nr_bind *bp, *bpnext ;
  399.     int i ;
  400.  
  401.     stop_timer(&Obsotimer);
  402.  
  403.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  404.         for (rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
  405.             rpnext = rp->next ;     /* save in case we free this route */
  406.             for (bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
  407.                 bpnext = bp->next ;    /* in case we free this binding */
  408.                 if (bp->flags & NRB_PERMANENT)    /* don't age these */
  409.                     continue ;
  410.                 if (--bp->obsocnt == 0) {        /* time's up! */
  411.                     if (bp->next != NULLNRBIND)
  412.                         bp->next->prev = bp->prev ;
  413.                     if (bp->prev != NULLNRBIND)
  414.                         bp->prev->next = bp->next ;
  415.                     else
  416.                         rp->routes = bp->next ;
  417.                     rp->num_routes-- ;            /* one less binding */
  418.                     np = bp->via ;                /* find the neighbor */
  419.                     xfree(bp) ;                    /* now we can free the bind */
  420.                     /* Check to see if we can free the neighbor */
  421.                     if (--np->refcnt == 0) {
  422.                         if (np->next != NULLNTAB)
  423.                             np->next->prev = np->prev ;
  424.                         if (np->prev != NULLNTAB)
  425.                             np->prev->next = np->next ;
  426.                         else {
  427.                             Nrnbr_tab[nrhash(np->call)] = np->next ;
  428.                         }
  429.                         xfree(np) ;    /* free the storage */
  430.                     }
  431.                 }
  432.             }
  433.             if (rp->num_routes == 0) {        /* did we free them all? */
  434.                 if (rp->next != NULLNRRTAB)
  435.                     rp->next->prev = rp->prev ;
  436.                 if (rp->prev != NULLNRRTAB)
  437.                     rp->prev->next = rp->next ;
  438.                 else
  439.                     Nrroute_tab[i] = rp->next ;
  440.  
  441.                 xfree(rp) ;
  442.             }
  443.         }
  444.     }
  445.     start_timer(&Obsotimer) ;
  446. }
  447.  
  448. /* Set timer for aging routes */
  449. static int
  450. doobsotimer(argc,argv,p)
  451. int argc;
  452. char *argv[];
  453. void *p;
  454. {
  455.     if(argc < 2){
  456.         tprintf("Obsotimer %lu/%lu s\n",
  457.             read_timer(&Obsotimer)/1000L,
  458.             dur_timer(&Obsotimer)/1000L);
  459.         return 0;
  460.     }
  461.     /* just in case it's already running */
  462.     stop_timer(&Obsotimer) ;
  463.     /* what to call on timeout */
  464.     Obsotimer.func = (void (*) __ARGS((void *))) doobsotick;
  465.     Obsotimer.arg = NULLCHAR;                        /* dummy value */
  466.     set_timer(&Obsotimer,atol(argv[1]) * 1000L);    /* set timer duration */
  467.     start_timer(&Obsotimer);                        /* and fire it up */
  468.     return 0;
  469. }
  470.  
  471. /* display a list of <callsign,interface> pairs from the filter
  472.  * list.
  473.  */
  474. static int
  475. donfdump(void)
  476. {
  477.     int i, column = 1 ;
  478.     struct nrnf_tab *fp ;
  479.     char buf[16] ;
  480.  
  481.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  482.         for (fp = Nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
  483.             pax25(buf,fp->neighbor) ;
  484.             tprintf("%-7s  %-8s  %-3d   ",
  485.              buf,Nrifaces[fp->iface].iface->name, fp->quality) ;
  486.             if (column++ == 3) {
  487.                 if(tputs("\n") == EOF)
  488.                     return 0;
  489.                 column = 1 ;
  490.             }
  491.         }
  492.  
  493.     if (column != 1)
  494.         tputs("\n");
  495.  
  496.     return 0 ;
  497. }
  498.  
  499. /* add an entry to the filter table */
  500. static int
  501. donfadd(argc,argv,p)
  502. int argc ;
  503. char *argv[] ;
  504. void *p;
  505. {
  506.     char neighbor[AXALEN] ;
  507.     int i ;
  508.     unsigned qual = atoi(argv[3]);
  509.  
  510.     /* format callsign */
  511.     if (setcall(neighbor,argv[1]) == -1) {
  512.         tputs(badnb);
  513.         return -1 ;
  514.     }
  515.  
  516.     if((i = nrif_lookup(argv[2],1)) == -1)
  517.         return -1;
  518.  
  519.     if(argc < 4)
  520.         qual = Nrifaces[i].quality;
  521.  
  522.     return nr_nfadd(neighbor,i,qual) ;
  523. }
  524.  
  525. /* drop an entry from the filter table */
  526. static int
  527. donfdrop(argc,argv,p)
  528. int argc ;
  529. char *argv[] ;
  530. void *p;
  531. {
  532.     char neighbor[AXALEN] ;
  533.     int i ;
  534.  
  535.     /* format neighbor callsign */
  536.     if (setcall(neighbor,argv[1]) == -1) {
  537.         tputs(badnb);
  538.         return -1 ;
  539.     }
  540.  
  541.     if((i = nrif_lookup(argv[2],1)) == -1)
  542.         return -1;
  543.  
  544.     return nr_nfdrop(neighbor,i) ;
  545. }
  546.  
  547. /* nodefilter mode subcommand */
  548. static int
  549. donfmode(argc,argv,p)
  550. int argc ;
  551. char *argv[] ;
  552. void *p;
  553. {
  554.     if (argc < 2) {
  555.         tputs("Filter mode: ");
  556.         switch (Nr_nfmode) {
  557.         case NRNF_NOFILTER:
  558.             tputs("none\n") ;
  559.             break ;
  560.         case NRNF_ACCEPT:
  561.             tputs("accept\n") ;
  562.             break ;
  563.         case NRNF_REJECT:
  564.             tputs("reject\n") ;
  565.             break ;
  566.         default:
  567.             tputs("unknown\n") ;
  568.         }
  569.     } else {
  570.         switch (tolower(argv[1][0])) {
  571.         case 'n':
  572.             Nr_nfmode = NRNF_NOFILTER ;
  573.             break ;
  574.         case 'a':
  575.             Nr_nfmode = NRNF_ACCEPT ;
  576.             break ;
  577.         case 'r':
  578.             Nr_nfmode = NRNF_REJECT ;
  579.             break ;
  580.         default:
  581.             tputs("Usage: mode <accept|reject|none>\n");
  582.             return -1 ;
  583.         }
  584.     }
  585.     return 0;
  586. }
  587.  
  588. /* nodefilter command multiplexer */
  589. static int
  590. donodefilter(argc,argv,p)
  591. int argc ;
  592. char *argv[] ;
  593. void *p;
  594. {
  595.     struct cmds Nfcmds[] = {
  596.         "add",    donfadd,    0, 3,
  597.             "netrom nodefilter add <neighbor> <iface> [<quality>]",
  598.         "drop",    donfdrop,    0, 3,
  599.             "netrom nodefilter drop <neighbor> <iface>",
  600.         "mode",    donfmode,    0, 0,    NULLCHAR,
  601.         NULLCHAR,
  602.     } ;
  603.  
  604.     if (argc < 2) {
  605.         donfdump() ;
  606.         return 0 ;
  607.     }
  608.     return subcmd(Nfcmds,argc,argv,p) ;
  609. }
  610.  
  611. /* netrom network packet time-to-live initializer */
  612. static int
  613. donrttl(argc, argv,p)
  614. int argc ;
  615. char *argv[] ;
  616. void *p;
  617. {
  618.     return setshort(&Nr_ttl,"TTL",argc,argv);
  619. }
  620.  
  621. /* verbose route broadcast */
  622. static int
  623. donrverbose(argc,argv,p)
  624. int argc ;
  625. char *argv[] ;
  626. void *p;
  627. {
  628.     return setbool(&Nr_verbose,"Verbose",argc,argv);
  629. }
  630.  
  631. /* allow automatic derating of netrom routes on link failure */
  632. static int
  633. donrderate(argc,argv,p)
  634. int argc ;
  635. char *argv[] ;
  636. void *p;
  637. {
  638.     extern int Nr_derate;
  639.  
  640.     return setbool(&Nr_derate,"Derate",argc,argv);
  641. }
  642.  
  643. /* promiscuous acceptance of broadcasts */
  644. static int
  645. donrpromisc(argc,argv,p)
  646. int argc ;
  647. char *argv[] ;
  648. void *p;
  649. {
  650.     extern int Nr_promisc;
  651.  
  652.     return setbool(&Nr_promisc,"Promiscuous",argc,argv);
  653. }
  654.  
  655. /* Initiate a NET/ROM transport connection */
  656. static int
  657. donrconnect(argc,argv,p)
  658. int argc ;
  659. char *argv[] ;
  660. void *p;
  661. {
  662.     char *np ;
  663.     struct sockaddr_nr lsocket, fsocket;
  664.     char alias[AXBUF];
  665.     struct session *sp;
  666.  
  667.     /* Get a session descriptor */
  668.     if ((sp = newsession(argv[1],NRSESSION,SPLIT | SWAP)) == NULLSESSION) {
  669.         tputs(Nosess);
  670.         return 1;
  671.     }
  672.  
  673.     if((sp->s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  674.         tputs(Nosocket);
  675.         goto quit;
  676.     }
  677.     lsocket.nr_family = AF_NETROM;
  678.     /* Set up our local username, bind would use Mycall instead */
  679.     memcpy(lsocket.nr_addr.user,Nr4user,AXALEN);
  680.     /* Putting anything else than Mycall here will not work */
  681.     memcpy(lsocket.nr_addr.node,Mycall,AXALEN);
  682.     bind(sp->s,(char *)&lsocket,SOCKSIZE);
  683.  
  684.     /* See if the requested destination could be an alias, and */
  685.     /* find and use it if it is.  Otherwise assume it is an ax.25 */
  686.     /* address. */
  687.  
  688.     if (putalias(alias,argv[1],0) != -1 &&
  689.         (np = find_nralias(alias)) != NULLCHAR) {
  690.         memcpy(fsocket.nr_addr.user,np,AXALEN) ;
  691.         memcpy(fsocket.nr_addr.node,np,AXALEN) ;
  692.     } else {    /* parse ax25 callsign */
  693.         /* Only the user callsign of the remote station is never used by */
  694.         /* NET/ROM, but it is needed for the psocket() call. */
  695.         setcall(fsocket.nr_addr.user,argv[1]);
  696.         setcall(fsocket.nr_addr.node,argv[1]);
  697.     }
  698.     fsocket.nr_family = AF_NETROM;
  699.     pax25(alias,fsocket.nr_addr.node);
  700.     if(!(tel_connect(sp,(char *)&fsocket,SOCKSIZE)))
  701.         return 0;
  702. quit:
  703.     keywait(NULLCHAR,1);
  704.     freesession(sp);
  705.     return 1;
  706. }
  707.  
  708. /* Reset a net/rom connection abruptly */
  709. static int
  710. donrreset(argc,argv,p)
  711. int argc;
  712. char *argv[];
  713. void *p;
  714. {
  715.     struct nr4cb *cb = (struct nr4cb *)shtop(argv[1]);
  716.  
  717.     if(!nr4valcb(cb)){
  718.         tputs(Notval);
  719.         return 1;
  720.     }
  721.     reset_nr4(cb);
  722.     return 0;
  723. }
  724.  
  725. /* Allows a manual forced close on a net/rom connection */
  726. static int
  727. donrclose(int argc,char *argv[],void *p)
  728. {
  729.     struct nr4cb *cb = (struct nr4cb *)shtop(argv[1]);
  730.  
  731.     if(!nr4valcb(cb)) {
  732.         tputs(Notval);
  733.         return 1;
  734.     }
  735.     disc_nr4(cb);
  736.     return 0;
  737. }
  738.  
  739. /* Force retransmission on a net/rom connection */
  740. static int
  741. donrkick(argc,argv,p)
  742. int argc;
  743. char *argv[];
  744. void *p;
  745. {
  746.     struct nr4cb *cb = (struct nr4cb *)shtop(argv[1]);
  747.  
  748.     if(!nr4valcb(cb)){
  749.         tputs(Notval);
  750.         return 1;
  751.     }
  752.     return kick_nr4(cb);
  753. }
  754.  
  755. /* netrom transport ACK delay timer */
  756. static int
  757. donracktime(argc, argv,p)
  758. int argc ;
  759. char *argv[] ;
  760. void *p;
  761. {
  762.     return setintrc(&Nr4acktime,"Ack delay",argc,argv,1,60);
  763. }
  764.  
  765. /* netrom transport choke timeout */
  766. static int
  767. donrchoketime(argc, argv,p)
  768. int argc ;
  769. char *argv[] ;
  770. void *p;
  771. {
  772.     return setintrc(&Nr4choketime,"Choke timeout",argc,argv,10,3600);
  773. }
  774.  
  775. /* netrom transport initial round trip time */
  776.  
  777. static int
  778. donrirtt(argc, argv,p)
  779. int argc ;
  780. char *argv[] ;
  781. void *p;
  782. {
  783.     return setintrc(&Nr4irtt,"IRTT",argc,argv,5,360);
  784. }
  785.  
  786. /* netrom transport receive queue length limit.  This is the */
  787. /* threshhold at which we will CHOKE the sender. */
  788.  
  789. static int
  790. donrqlimit(argc, argv,p)
  791. int argc ;
  792. char *argv[] ;
  793. void *p;
  794. {
  795.     return setintrc(&Nr4qlimit,"Queue limit",argc,argv,1,4096);
  796. }
  797.  
  798. /* Display or change our NET/ROM username */
  799. static int
  800. donruser(argc,argv,p)
  801. int argc;
  802. char *argv[];
  803. void *p;
  804. {
  805.     char buf[AXBUF];
  806.  
  807.     if(argc < 2){
  808.         tprintf("%s\n",pax25(buf,Nr4user));
  809.         return 0;
  810.     }
  811.     if(setcall(Nr4user,argv[1]) == -1)
  812.         return -1;
  813.     Nr4user[ALEN] |= E;
  814.     return 0;
  815. }
  816.  
  817. /* netrom transport maximum window.  This is the largest send and */
  818. /* receive window we may negotiate */
  819.  
  820. static int
  821. donrwindow(argc, argv,p)
  822. int argc ;
  823. char *argv[] ;
  824. void *p;
  825. {
  826.     return setintrc(&Nr4window,"Window",argc,argv,1,NR4MAXWIN);
  827. }
  828.  
  829. /* netrom transport maximum retries.  This is used in connect and */
  830. /* disconnect attempts; I haven't decided what to do about actual */
  831. /* data retries yet. */
  832.  
  833. static int
  834. donrretries(argc, argv,p)
  835. int argc ;
  836. char *argv[] ;
  837. void *p;
  838. {
  839.     return setshort(&Nr4retries,"Retry limit",argc,argv);
  840. }
  841.  
  842. /* Display the status of NET/ROM connections */
  843.  
  844. static int
  845. donrstatus(argc, argv,p)
  846. int argc ;
  847. char *argv[] ;
  848. void *p;
  849. {
  850.     int i ;
  851.     struct nr4cb *cb ;
  852.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  853.  
  854.     if (argc < 2) {
  855.         tputs("&NRCB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  856.         for (i = 0 ; i < NR4MAXCIRC ; i++) {
  857.             if ((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  858.                 continue ;
  859.             pax25(luser,cb->local.user) ;
  860.             pax25(ruser,cb->remote.user) ;
  861.             pax25(node,cb->remote.node) ;
  862.             if(tprintf("%lx    %3d %5d %5d %9s  %9s %-9s %s\n",
  863.              ptol(cb), cb->nbuffered, len_q(cb->txq),
  864.              len_p(cb->rxq), luser, ruser, node,
  865.              Nr4states[cb->state]) == EOF)
  866.                 break;
  867.         }
  868.         return 0 ;
  869.     }
  870.  
  871.     cb = (struct nr4cb *)shtop(argv[1]) ;
  872.     if (!nr4valcb(cb)) {
  873.         tputs(Notval);
  874.         return 1 ;
  875.     }
  876.  
  877.     donrdump(cb) ;
  878.     return 0 ;
  879. }
  880.  
  881. /* Dump one control block */
  882.  
  883. void
  884. donrdump(cb)
  885. struct nr4cb *cb ;
  886. {
  887.     char luser[AXBUF], ruser[AXBUF], node[AXBUF] ;
  888.     unsigned seq ;
  889.     struct nr4txbuf *b ;
  890.     struct timer *t ;
  891.  
  892.     pax25(luser,cb->local.user) ;
  893.     pax25(ruser,cb->remote.user) ;
  894.     pax25(node,cb->remote.node) ;
  895.  
  896.     tprintf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  897.            luser, cb->mynum, cb->myid, ruser, node,
  898.            cb->yournum, cb->yourid, Nr4states[cb->state]) ;
  899.  
  900.     tprintf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  901.            cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
  902.            len_p(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
  903.  
  904.     tprintf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\nTACK: ",
  905.            cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
  906.            len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
  907.  
  908.     if (run_timer(&cb->tack))
  909.         tprintf("%lu", read_timer(&cb->tack)) ;
  910.     else
  911.         tputs("-") ;
  912.     tprintf("/%lu ms  TChoke: ", dur_timer(&cb->tack)) ;
  913.  
  914.     if (run_timer(&cb->tchoke))
  915.         tprintf("%lu", read_timer(&cb->tchoke)) ;
  916.     else
  917.         tputs("-") ;
  918.     tprintf("/%lu ms  TCD: ", dur_timer(&cb->tchoke)) ;
  919.  
  920.     if (run_timer(&cb->tcd))
  921.         tprintf("%lu", read_timer(&cb->tcd)) ;
  922.     else
  923.         tputs("-") ;
  924.  
  925.     tprintf("/%lu ms\nTries: %u  Inactive: %ld/%ld sec",
  926.         dur_timer(&cb->tcd),
  927.         cb->cdtries,
  928.         read_timer(&cb->inactivity)/1000L,
  929.         dur_timer(&cb->inactivity)/1000L);
  930.  
  931.     if(cb->blevel)
  932.         tprintf("  Backoff Level %u",cb->blevel);
  933.  
  934.     tprintf("\nSRTT %ld ms Mean dev %ld ms\n", cb->srtt, cb->mdev) ;
  935.  
  936.     /* If we are connected and the send window is open, display */
  937.     /* the status of all the buffers and their timers */
  938.     if (cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  939.         tputs("TxBuffers:  Seq  Size  Tries  Timer\n") ;
  940.  
  941.         for (seq = cb->ackxpected ;
  942.              nr4between(cb->ackxpected, seq, cb->nextosend) ;
  943.              seq = (seq + 1) & NR4SEQMASK) {
  944.  
  945.             b = &cb->txbufs[seq % cb->window] ;
  946.             t = &b->tretry ;
  947.  
  948.             if(tprintf("            %3u   %3d  %5d  %lu/%lu\n",
  949.               seq, len_p(b->data), b->retries + 1, read_timer(t), dur_timer(t))
  950.               == EOF)
  951.                 break;
  952.         }
  953.     }
  954. }
  955.  
  956. static int
  957. dominquality(argc,argv,p)
  958. int argc ;
  959. char *argv[] ;
  960. void *p ;
  961. {
  962.     return setintrc(&(int16)Nr_autofloor,"MinQual",argc,argv,1,255);
  963. }
  964.  
  965. /* Switch on/off saving of netrom routes to disk */
  966. static int
  967. doroutesave(argc,argv,p)
  968. int argc ;
  969. char *argv[] ;
  970. void *p;
  971. {
  972.     return setbool(&Nr_save,"NET/ROM Route Save",argc,argv);
  973. }
  974.  
  975. static char * near
  976. getarg(char *line)
  977. {
  978.   char  *arg;
  979.   int  c;
  980.   static char  *p;
  981.  
  982.   if (line) p = line;
  983.   while (isspace(uchar(*p))) p++;
  984.   arg = p;
  985.   while (*p && !isspace(uchar(*p))) {
  986.     c = (uchar(*p));
  987.     *p++ = c;
  988.   }
  989.   if (*p) *p++ = '\0';
  990.   return arg;
  991. }
  992.  
  993. /*
  994.  * Load saved NET/ROM routes - called at startup
  995.  */
  996. int
  997. donrload(void)
  998. {
  999.     FILE *fn;
  1000.     int quality, i, j;
  1001.     char buff[LINELEN], *alias = 0, *dest, *type, *iface, *neighbor;
  1002.     char ax25_alias[AXALEN], ax25_dest[AXALEN], ax25_nbor[AXALEN], *ptr;
  1003.  
  1004.     if((fn = Fopen(Nrroutefile,READ_TEXT,0,1)) == NULLFILE)
  1005.         return 1;
  1006.  
  1007.     while(fgets(buff,LINELEN,fn) != NULL) {
  1008.         alias = dest = type = iface = neighbor = 0;
  1009.         quality = 0;
  1010.         if((ptr = strchr(buff,':')) == 0){
  1011.             *alias = '\0';
  1012.             dest = getarg(buff);
  1013.         } else {
  1014.             *ptr = ' ';
  1015.             alias = getarg(buff);
  1016.             dest = getarg(0);
  1017.         }
  1018.         type = getarg(0);
  1019.         quality = atoi(getarg(0));
  1020.         getarg(0);
  1021.         iface = getarg(0);
  1022.         neighbor = getarg(0);
  1023.  
  1024.         /* find interface */
  1025.         for(i = 0 ; i < Nr_numiface ; i++)
  1026.             if(!strcmp(Nrifaces[i].iface->name,iface))
  1027.                 break ;
  1028.  
  1029.         if(i == Nr_numiface) {
  1030.             tprintf(Badif,iface);
  1031.             continue;
  1032.         }
  1033.  
  1034.         /* Convert to NET/ROM routing table formats */
  1035.         putalias(ax25_alias, alias, 0);
  1036.         setcall(ax25_dest, dest);
  1037.         setcall(ax25_nbor, neighbor);
  1038.  
  1039.         /* get and check quality value */
  1040.         if(quality  > 255)
  1041.             quality = 255;
  1042.  
  1043.         if (*type == 'P')
  1044.             j = 0;
  1045.         else
  1046.             j = 1;
  1047.  
  1048.         nr_routeadd(ax25_alias,ax25_dest,i,quality,ax25_nbor,!j,j);
  1049.     }
  1050.     Fclose(fn);
  1051.     return 0;
  1052. }
  1053.  
  1054. /*
  1055.  * Save NET/ROM routes in file for reading when we start up again.
  1056.  * This function is called at each tick of the netrom obsotimer.
  1057.  *
  1058.  */
  1059.  
  1060. int
  1061. donrsave(void)
  1062. {
  1063.     struct nrroute_tab *rp ;
  1064.     struct nr_bind *bp ;
  1065.     struct nrnbr_tab *np ;
  1066.     char neighbor[AXBUF], buf[18], *cp;
  1067.     int i;
  1068.     FILE *fn;
  1069.  
  1070.     if((fn = Fopen(Nrroutefile,WRITE_TEXT,0,1)) == NULLFILE)
  1071.         return 1;
  1072.  
  1073.     for(i = 0 ; i < NRNUMCHAINS ; i++){
  1074.         for(rp = Nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next){
  1075.             sprintf(buf,"%.*s",AXALEN,rp->alias) ;
  1076.             /* remove trailing spaces */
  1077.             if((cp = strchr(buf,' ')) == NULLCHAR)
  1078.                 cp = &buf[strlen(buf)] ;
  1079.             if(cp != buf)        /* don't include colon for null alias */
  1080.                 *cp++ = ':' ;
  1081.             for(bp = rp->routes; bp != NULLNRBIND; bp = bp->next) {
  1082.                 pax25(cp,rp->call) ;
  1083.                 fprintf(fn,"%-16s  ",buf) ;
  1084.                 np = bp->via ;
  1085.                 fprintf(fn,"%1s %3d  %3d  %-8s  %s\n",
  1086.                   (bp->flags & NRB_PERMANENT ? "P" :
  1087.                   bp->flags & NRB_RECORDED ? "R" : "X"),
  1088.                   bp->quality,bp->obsocnt,
  1089.                   Nrifaces[np->iface].iface->name,
  1090.                   pax25(neighbor,np->call));
  1091.             }
  1092.         }
  1093.     }
  1094.     Fclose(fn);
  1095.     return 0;
  1096. }
  1097.  
  1098. /* Route command multiplexer */
  1099. static int
  1100. donrroute(argc, argv,p)
  1101. int argc ;
  1102. char *argv[] ;
  1103. void *p;
  1104. {
  1105.     struct cmds Routecmds[] = {
  1106.         "add",    dorouteadd,        0, 6,
  1107.             "netrom route add <alias> <destination> <iface> <quality> <neighbor>",
  1108.         "drop",    doroutedrop,     0, 4,
  1109.             "netrom route drop <destination> <neighbor> <iface>",
  1110.         "info", dorouteinfo,     0, 2,
  1111.             "netrom route info <destination>",
  1112.         "save", doroutesave,    0, 0,
  1113.             "netrom route save [<0|1>]",
  1114.         NULLCHAR,
  1115.     } ;
  1116.  
  1117.     if (argc < 2) {
  1118.         return doroutedump(9,0,p);
  1119.     }
  1120.     if(argc == 3 && stricmp(argv[2],"tcp") == 0) {
  1121.         return doroutedump(0,0,p);
  1122.     }
  1123.     return subcmd(Routecmds,argc,argv,p) ;
  1124. }
  1125.  
  1126. /* Command multiplexer */
  1127. int
  1128. donetrom(argc,argv,p)
  1129. int argc ;
  1130. char *argv[] ;
  1131. void *p;
  1132. {
  1133.     struct cmds Nrcmds[] = {
  1134.     "acktime",        donracktime,    0, 0,    NULLCHAR,
  1135.     "bcnodes",        dobcnodes,        0, 2,    "netrom bcnodes <iface> [<call>]",
  1136.     "connect",        donrconnect, 1024, 2,    "netrom connect <node>",
  1137.     "choketime",    donrchoketime,    0, 0,    NULLCHAR,
  1138.     "close",        donrclose,        0, 2,    "netrom close <nrcb>",
  1139.     "derate",        donrderate,        0, 0,    NULLCHAR,
  1140.     "interface",    dointerface,    0, 4,
  1141.         "netrom interface <iface> <alias> <quality> [<call>]",
  1142.     "irtt",            donrirtt,        0, 0,    NULLCHAR,
  1143.     "kick",            donrkick,        0, 2,    "netrom kick <nrcb>",
  1144.     "minquality",    dominquality,    0, 0,    NULLCHAR,
  1145.     "nodefilter",    donodefilter,    0, 0,    NULLCHAR,
  1146.     "nodetimer",    donodetimer,    0, 0,    NULLCHAR,
  1147.     "obsotimer",    doobsotimer,    0, 0,    NULLCHAR,
  1148.     "promiscuous",    donrpromisc,    0, 0,    NULLCHAR,
  1149.     "qlimit",        donrqlimit,        0, 0,    NULLCHAR,
  1150.     "reset",        donrreset,        0, 2,    "netrom reset <nrcb>",
  1151.     "retries",        donrretries,    0, 0,    NULLCHAR,
  1152.     "route",        donrroute,        0, 0,    NULLCHAR,
  1153.     "status",        donrstatus,        0, 0,    NULLCHAR,
  1154.     "ttl",            donrttl,        0, 0,    NULLCHAR,
  1155.     "user",            donruser,        0, 0,    NULLCHAR,
  1156.     "verbose",        donrverbose,    0, 0,    NULLCHAR,
  1157.     "window",        donrwindow,        0, 0,    NULLCHAR,
  1158.     NULLCHAR,
  1159.     } ;
  1160.     return subcmd(Nrcmds,argc,argv,p) ;
  1161. }
  1162.  
  1163. #endif /* NETROM */
  1164.